﻿"""
    Document   : jamendo_rpc.py
    Author     : Ángel Fernández Pineda
    Copyright  : 2011, Ángel Fernández Pineda, Spain
    License    : GNU General Public License - see LICENSE.TXT
    Description: Client library to Jamendo's Remote Procedure Call service
"""
"""
    This file is free software: you can redistribute
    it and/or modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation, either version 3 of the License,
    or (at your option) any later version.

    This file is distributed in the hope that it will
    be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with the "Jamendo Radio plugin for XBMC".
    If not, see <http://www.gnu.org/licenses/>.
"""

import urllib2
import time

## URL to Jamendo's RPC service
_RPC_jamendo_plain = "http://api.jamendo.com/get2/%s/%s/plain/?%s"
_RPC_jamendo_plain_join = "http://api.jamendo.com/get2/%s/%s/plain/%s/?%s"

## Auxiliary (private) functions

def __listToStr(listOfFields,separator="+"):
    """
     Create a string from a list of strings

     @param listOfFields list
         List of strings
     @param separator string
         Character to separate two strings
     @return string
         A string like 'field1+field2+field3' where '+' is the separator
    """
    if (type(listOfFields)==list) or (type(listOfFields)==tuple):
        fieldsStr = ""
        sep = ""
        for field in listOfFields:
            fieldsStr = "%s%s%s" % (fieldsStr,sep,field)
            sep=separator
        return fieldsStr
    else:
        return str(listOfFields)
#end def

def __conditionsToStr(conditions):
    """
     Create a URL-like string representation of given conditions

     @param conditions dictionary
         Key-value pairs. Values can be tuples
     @return string
         A string like 'id=3+5+77&n=40'
    """
    resultList = []
    keys = conditions.keys()
    values = conditions.values()
    for index in range(len(keys)):
        cond = "%s=%s" % (str(keys[index]),__listToStr(values[index]))
        resultList.append(cond)
    return __listToStr(resultList,"&")        
#end def
        
def __plainTextToList(textline):
  """
    Parse fields from a line of a plain text response from Jamendo API

    @param textline string
        A response line
    @return list
        List of string values
  """
  return textline.replace("\n","").split("\t")
#end def

__last_time = time.clock() # auxiliary variable, sorry, must be global
def __ensureDelay(seconds):
    """
     Ensure that a minimun time has passed since last call

     @param seconds float
         Time to wait
    """
    global __last_time
    diff = time.clock()-__last_time
    if (diff<seconds):
        time.sleep(seconds-diff)
    __last_time = time.clock()
#end def

def __jamendo_rpc_plain(url,fieldNames):
    """
      Retrieve a plain response from Jamendo and parse it

      @param url string
          Url to Jamendo's RPC API
      @param fieldNames
          A list of field names to build up a dictionary.
          Must match the number of fields in the query
      @return list
          A list of dictionaries.
    """
    __ensureDelay(1) # required to comply with Jamendo's Terms of Use
    strm = urllib2.urlopen(url)
    try:
        line = strm.readline()
        result = []
        while (len(line)>0):
            values = __plainTextToList(line)
            result.append(dict(zip(fieldNames,values)))
            line = strm.readline()
        #end while
    finally:
        strm.close()
    return result
#end def


# RPC query
  
def query(fields,table,conditions):
    """
     Call Jamendo's RPC GET2 service

     @param fields list
         A list of field names (strings)
     @param table string or tuple
         if a string, a table name
         if a tuple, a pair of table names for SQL-like joint query
     @conditions dictionary
         A dictionary of field=value conditions
         To query for multiple values use a tuple. For example:
         { "tag": ("techno","hard","ambient") }
    """
    fieldsStr = __listToStr(fields)
    conditionsStr = __conditionsToStr(conditions)
    if (type(table)==str):
        url = _RPC_jamendo_plain % (fieldsStr,table,conditionsStr)
    elif (type(table)==tuple) and (len(table)==2):
        url = _RPC_jamendo_plain_join % (
            fieldsStr,table[0],table[1],conditionsStr)
    else:
        raise TypeError
    return __jamendo_rpc_plain(url,fields)
#end def
